package com.chq.version.util;

import com.chq.version.log.LogMonitor;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.*;

import java.io.File;
import java.util.*;

public class SVNUtil {
    /**
     * 通过不同的协议初始化版本库
     */
    public static void initSVNService() {
        DAVRepositoryFactory.setup();
        SVNRepositoryFactoryImpl.setup();
        FSRepositoryFactory.setup();
    }


    /**
     * 登录SVN
     *
     * @param svnRoot  SVN地址
     * @param username 用户名
     * @param password 密码
     * @return SVNClientManager实例
     */
    public static SVNRepository getSVNRepository(String svnRoot, String username,
                                                 String password) {
        initSVNService();
        // 定义svn版本库的URL。
        SVNURL repositoryURL;
        // 定义版本库。
        SVNRepository repository = null;
        // 实例化版本库类
        try {
            // 获取SVN的URL。
            repositoryURL = SVNURL.parseURIEncoded(svnRoot);
            // 根据URL实例化SVN版本库。
            repository = SVNRepositoryFactory.create(repositoryURL);
        } catch (SVNException svne) {
            // 打印版本库实例创建失败的异常。
            System.err.println("创建版本库实例时失败，版本库的URL是 '" + svnRoot + "': "
                    + svne.getMessage());
            System.exit(1);
        }
        // 对版本库设置认证信息。
        ISVNAuthenticationManager authManager = SVNWCUtil.createDefaultAuthenticationManager(username,
                password.toCharArray());
        // 创建身份验证管理器
        repository.setAuthenticationManager(authManager);
        return repository;
    }

    /**
     * 登录SVN
     *
     * @param svnRoot  SVN地址
     * @param username 用户名
     * @param password 密码
     * @return SVNClientManager实例
     */
    public static SVNClientManager login(String svnRoot, String username,
                                         String password) {
        // 定义版本库。
        SVNRepository repository = getSVNRepository(svnRoot, username,
                password);
        // 对版本库设置认证信息。
        ISVNAuthenticationManager authManager = SVNWCUtil
                .createDefaultAuthenticationManager(username,
                        password.toCharArray());
        // 创建身份验证管理器
        repository.setAuthenticationManager(authManager);
        DefaultSVNOptions options = SVNWCUtil.createDefaultOptions(true);
        return SVNClientManager.newInstance(options, authManager);
    }

    /**
     * 获取项目SVN最新版本
     *
     * @param repository SVN版本库实例
     * @return 版本号
     * @throws SVNException SVN异常
     */
    public static long getLatestRevision(SVNRepository repository) throws SVNException {
        //获得版本库的最新版本树
        long latestRevision = -1;
        try {
            latestRevision = repository.getLatestRevision();
        } catch (SVNException svne) {
            System.err.println("获取最新版本号时出错: " + svne.getMessage());
            System.exit(1);
        }
        return latestRevision;
    }

    /**
     * 递归获取版本库中某一目录下的所有条目。
     *
     * @param repository SVN版本库实例
     * @param path       文件夹
     * @param revision   起始版本
     * @throws SVNException SVN异常
     */
    public static List<String> listEntries(SVNRepository repository,
                                           String path, long revision) throws SVNException {
        return listEntries(repository, path, revision, null);
    }

    /**
     * 递归获取版本库中某一目录下的所有条目。
     *
     * @param repository SVN版本库实例
     * @param path       文件夹
     * @param revision   起始版本
     * @param tempList   临时变量，必须为null
     * @throws SVNException SVN异常
     */
    private static List<String> listEntries(SVNRepository repository,
                                            String path, long revision, List<String> tempList)
            throws SVNException {
        if (tempList == null) {
            tempList = new ArrayList<String>();
        }
        // 获取版本库的path目录下的所有条目。参数－1表示是最新版本。
        @SuppressWarnings("rawtypes")
        Collection entries = repository.getDir(path, -1, null,
                (Collection) null);
        @SuppressWarnings("rawtypes")
        Iterator iterator = entries.iterator();
        while (iterator.hasNext()) {
            SVNDirEntry entry = (SVNDirEntry) iterator.next();
            if (entry.getRevision() >= revision) {
                if (entry.getName().contains(".")) {
                    tempList.add("/" + ("".equals(path) ? "" : path + "/")
                            + entry.getName());
                }
            }
            // 检查此条目是否为目录，如果为目录递归执行
            if (entry.getKind() == SVNNodeKind.DIR) {
                listEntries(repository, ("".equals(path)) ? entry.getName()
                        : path + "/" + entry.getName(), revision, tempList);
            }
        }
        return tempList;
    }

    /**
     * 将最新代码拷贝到临时文件夹
     *
     * @param repository SVN版本库实例
     * @param revision   版本号
     * @param destPath   临时文件存储路径
     * @param itemsPath  项目路径
     */
    public static void copyCodeToDestPath(SVNRepository repository, long revision,
                                          String destPath, String itemsPath) {
        String filePath = "";
        List<String> list = new ArrayList<String>();
        try {
            //递归获取版本库中某一目录下的所有条目。
            list = SVNUtil.listEntries(repository, "", revision);
        } catch (SVNException svne) {
            System.err.println("获取版本树时发生错误: " + svne.getMessage());
            System.exit(1);
        }
        if (list.size() > 0) {
            for (String file : list) {
                file = file.replaceAll("/", "\\\\");
                if (file.contains("\\src")) {
                    file = file.replaceAll(".java", ".class");
                    filePath = "\\WEB-INF\\classes" + file.substring(4);
                } else if (file.contains("\\resources")) {
                    filePath = "\\WEB-INF\\classes" + file.substring(10);
                } else if (file.contains("\\WebRoot")) {
                    filePath = file.substring(8);
                } else {
                    filePath = file;
                }
                FileUtil.copyFile(itemsPath + filePath, destPath + filePath,
                        true);
            }
        }
    }

    /**
     * 检出项目
     *
     * @param svnUrl       SVN地址
     * @param svnUsername  SVN登录名
     * @param svnPassword  SVN密码
     * @param checkOutPath 检出到指定目录
     */
    public static void checkOut(String svnUrl, String svnUsername, String svnPassword, String checkOutPath) {
        //相关变量赋值
        SVNURL repositoryURL = null;
        try {
            repositoryURL = SVNURL.parseURIEncoded(svnUrl);
        } catch (SVNException e) {
            //
        }
        ISVNOptions options = SVNWCUtil.createDefaultOptions(true);
        //实例化客户端管理类
        SVNClientManager ourClientManager = SVNClientManager.newInstance(
                (DefaultSVNOptions) options, svnUsername, svnPassword);

        //要把版本库的内容check out到的目录
        File checkOutDir = new File(checkOutPath);
        if (!checkOutDir.exists()) {
            FileUtil.createFolder(checkOutPath);
        }

        //通过客户端管理类获得updateClient类的实例。
        SVNUpdateClient updateClient = ourClientManager.getUpdateClient();

        updateClient.setIgnoreExternals(false);

        //执行check out 操作，返回工作副本的版本号。
        long workingVersion = -1;
        try {
            workingVersion = updateClient
                    .doCheckout(repositoryURL, checkOutDir, SVNRevision.HEAD, SVNRevision.HEAD, SVNDepth.INFINITY, false);
        } catch (SVNException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("把版本：" + workingVersion + " check out 到目录：" + checkOutPath + "中。");
    }


    public static void doUpdate(String itemsPath, String name, String password) {
        ISVNOptions options = SVNWCUtil.createDefaultOptions(true);
        //实例化客户端管理类
        SVNClientManager ourClientManager = SVNClientManager.newInstance(
                (DefaultSVNOptions) options, name, password);
        //要更新的文件
        File updateFile = new File(itemsPath);
        //获得updateClient的实例
        SVNUpdateClient updateClient = ourClientManager.getUpdateClient();
        updateClient.setIgnoreExternals(false);
        //执行更新操作
        long versionNum = 0;
        try {
            versionNum = updateClient.doUpdate(updateFile, SVNRevision.HEAD, SVNDepth.INFINITY, false, false);
        } catch (SVNException e) {
            if (e.getMessage().contains("run 'svn cleanup' first")) {
                doCleanup(itemsPath, name, password);
                doUpdate(itemsPath, name, password);
            } else {
                e.printStackTrace();
            }
        }
        LogMonitor.addLog("工作副本更新后的版本：" + versionNum);
    }

    private static void doCleanup(String itemsPath, String name, String password) {
        ISVNOptions options = SVNWCUtil.createDefaultOptions(true);
        //实例化客户端管理类
        SVNClientManager ourClientManager = SVNClientManager.newInstance(
                (DefaultSVNOptions) options, name, password);
        //要更新的文件
        File file = new File(itemsPath);
        SVNWCClient svnwcClient = ourClientManager.getWCClient();
        svnwcClient.setIgnoreExternals(false);
        try {
            svnwcClient.doCleanup(file);
        } catch (SVNException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        //加载配置文件
        Map<String, String> map = PropertiesUtil.getMap("conn");
        try {
            Long d = getLatestRevision(getSVNRepository(map.get("svn.url"), map.get("svn.username"), map.get("svn.password")));
            System.out.println(d);
        } catch (SVNException e) {
            e.printStackTrace();
        }
        SVNUtil.initSVNService();
        //连接SVN
        SVNUtil.doUpdate(map.get("path.version") + "\\items", map.get("svn.username"),
                map.get("svn.password"));
    }
}
